package crmdna.member;

import static crmdna.common.OfyService.ofy;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.googlecode.objectify.Work;

import crmdna.client.Client;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.common.Utils;
import crmdna.member.MemberCore.MemberProp;
import crmdna.programtype.ProgramType;
import crmdna.user.User;

public class UnverifiedProgram {
	public static List<UnverifiedProgramProp> getUnverifiedPrograms(
			String client, long memberId, String login) {

		// this is just a convenience function. it uses the corresponding array
		// function
		Member.safeGet(client, memberId, login);

		List<Long> memberIds = new ArrayList<>();
		memberIds.add(memberId);

		Map<Long, List<UnverifiedProgramProp>> map = getUnverifiedPrograms(
				client, memberIds);

		if (map.size() == 0)
			return null;

		if (!map.containsKey(memberId)) {
			// should never get here
			throw new APIException(Status.ERROR_INTERNAL,
					"Cannot find memberId [" + memberId
							+ "] in map returned by getUnverifiedPrograms");
		}

		return map.get(memberId);
	}

	public static Map<Long, List<UnverifiedProgramProp>> getUnverifiedPrograms(
			String client, List<Long> memberIds) {

		Map<Long, MemberEntity> membersMap = ofy(client).load()
				.type(MemberEntity.class).ids(memberIds);

		Map<Long, List<UnverifiedProgramProp>> unverifiedProgramsMap = new HashMap<>();

		for (Long memberId : membersMap.keySet()) {
			MemberEntity memberEntity = membersMap.get(memberId);
			String json = memberEntity.listUnverfiedProgramPropJson;

			Gson gson = new Gson();
			Type type = new TypeToken<List<UnverifiedProgramProp>>() {
			}.getType();

			List<UnverifiedProgramProp> list = gson.fromJson(json, type);
			unverifiedProgramsMap.put(memberId, list);
		}

		return unverifiedProgramsMap;
	}

	public static MemberProp saveUnverifiedPrograms(final String client,
			final long memberId,
			final List<UnverifiedProgramProp> unverifiedPrograms,
			final String login) {

		Client.ensureValidClient(client);
		User.ensureValidUser(client, login);

		// program type should be valid. date should be correct format.
		Set<Long> programTypeIds = new HashSet<>();
		for (UnverifiedProgramProp uvp : unverifiedPrograms) {
			programTypeIds.add(uvp.programTypeId);
			Utils.ensureFormatYYYYMMDD(uvp.dateYYYYMM);
		}

		ProgramType.ensureValid(client, programTypeIds);

		Collections.sort(unverifiedPrograms);

		MemberEntity memberEntity = ofy(client).transact(
				new Work<MemberEntity>() {

					@Override
					public MemberEntity run() {
						MemberEntity memberEntity = Member.safeGet(client,
								memberId, login);
						Gson gson = new Gson();
						memberEntity.listUnverfiedProgramPropJson = gson
								.toJson(unverifiedPrograms);

						ofy(client).save().entity(memberEntity).now();
						return memberEntity;
					}
				});

		MemberCore.populateDependantFields(client, memberEntity);

		MemberProp memberProp = memberEntity.toProp();
		memberProp.unverifiedProgramProps = unverifiedPrograms;
		return memberProp;
	}

	static List<UnverifiedProgramProp> getUnverifiedProgramPropsFromJson(
			String json) {
		Gson gson = new Gson();
		Type type = new TypeToken<List<UnverifiedProgramProp>>() {
		}.getType();

		List<UnverifiedProgramProp> list = gson.fromJson(json, type);

		return list;
	}
}
